﻿    Declare Function SetupDiCreateDeviceInfoList Lib "setupapi.dll" (ByRef ClassGuid As System.Guid, ByVal hwndParent As Integer) As Integer
    Declare Function SetupDiGetClassDevsEx Lib "setupapi.dll" (ByRef ClassGUID As System.Guid, ByVal Enumerator As Integer, ByVal hwndParent As Integer, ByVal code As Integer, ByVal List As Integer, ByVal Machine As String, ByVal Reserved As Integer) As Integer
    Declare Auto Function SetupDiEnumDeviceInterfaces Lib "setupapi.dll" (ByVal DeviceInfoSet As IntPtr, ByRef DeviceInfoData As SP_DEVINFO_DATA, ByRef InterfaceClassGuid As Guid, ByVal MemberIndex As UInteger, ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA) As Boolean
    Declare Auto Function SetupDiGetDeviceInterfaceDetail Lib "setupapi.dll" Alias "SetupDiGetDeviceInterfaceDetailW" (ByVal hDevInfo As IntPtr, ByRef deviceInterfaceData As SP_DEVICE_INTERFACE_DATA, ByRef deviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA, ByVal deviceInterfaceDetailDataSize As Int32, ByRef requiredSize As Int32, ByRef deviceInfoData As SP_DEVINFO_DATA) As Boolean


    <StructLayout(LayoutKind.Sequential, Pack:=1)> _
    Structure SP_DEVICE_INTERFACE_DETAIL_DATA
        Public cbSize As UInteger
        Public DevicePath As String
    End Structure

    <StructLayout(LayoutKind.Sequential)> _
    Structure SP_DEVINFO_DATA
        Public cbSize As UInteger
        Public ClassGuid As Guid
        Public DevInst As UInteger
        Public Reserved As IntPtr
    End Structure

    <StructLayout(LayoutKind.Sequential)> _
    Structure PORT_INFO_2
        Public pPortName As String
        Public pMonitorName As String
        Public pDescription As String
        Public fPortType As Integer
        Public Reserved As Integer
    End Structure

    Private Enum SetupErrors
        ERROR_INSUFFICIENT_BUFFER = 122
        ERROR_INVALID_DATA = 13&
        ERROR_NO_MORE_ITEMS = 259&
    End Enum

    Declare Auto Function EnumPorts Lib "winspool.drv" Alias "EnumPortsA" (ByVal pName As String, ByVal level As Integer, ByVal lpbPorts As IntPtr, ByVal cbBuf As Integer, ByRef pcbNeeded As Integer, ByRef pcReturned As Integer) As Boolean

Declare Auto Function SetupDiClassGuidsFromName Lib "setupapi.dll" (ByVal ClassName As System.Text.StringBuilder, ByRef ClassGuids As Guid, ByVal ClassGuidSize As Integer, ByRef ClassGuidRequiredSize As Integer) As Boolean

Public Shared Function GetPorts6() As serPort()
    Dim portGuid As Guid
    Dim cbSize As Integer
    SetupDiClassGuidsFromName(New System.Text.StringBuilder("Ports"), Nothing, 0, cbSize)
    SetupDiClassGuidsFromName(New System.Text.StringBuilder("Ports"), portGuid, cbSize, cbSize)
    'Dim hDevInfoSet As SP_DEVINFO_DATA = SetupDiGetClassDevs(

End Function


Public Shared Function GetPorts5() As serPort()
    Dim cbNeeded As Integer
    Dim dwPorts As Integer
    Dim pPorts() As PORT_INFO_2
    EnumPorts(vbNullString, 2, Nothing, 0, cbNeeded, dwPorts)

    Dim tmpPtr As IntPtr = Marshal.AllocHGlobal(cbNeeded + 1)
    If EnumPorts(vbNullString, 2, tmpPtr, cbNeeded, cbNeeded, dwPorts) Then
        'pPorts = tmpPtr
        Dim currentPort As IntPtr = tmpPtr
        ReDim pPorts(dwPorts)
        For i As Integer = 1 To dwPorts
            pPorts(i) = Marshal.PtrToStructure(currentPort, GetType(PORT_INFO_2))
            currentPort = IntPtr.op_Explicit(currentPort.ToInt32 + Marshal.SizeOf(GetType(PORT_INFO_2)))
        Next
    End If

End Function


Public Shared Function GetPorts4() As serPort()
    Dim hDevInfo As IntPtr = SetupDiGetClassDevs(GUID_DEVCLASS_PORTS, 0, IntPtr.Zero, DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE)
    'Dim hDevInfo As IntPtr = SetupDiGetClassDevs(Nothing, 0, IntPtr.Zero, DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE)
    'Dim devInfo As SP_DEVINFO_DATA = New SP_DEVINFO_DATA()
    Dim devInfo As SP_DEVICE_INTERFACE_DATA = New SP_DEVICE_INTERFACE_DATA()
    devInfo.cbSize = Marshal.SizeOf(GetType(SP_DEVICE_INTERFACE_DATA))
    Dim sDevice As String = ""
    If hDevInfo.ToInt32 = -1 Then
        Return Nothing
    End If
    Dim nCount As Integer = 0
    Dim bResult As Boolean = True
    Do While bResult
        bResult = SetupDiEnumDeviceInfo(hDevInfo, nCount, devInfo)
        'bResult = SetupDiEnumDeviceInterfaces(hDevInfo, Nothing, GUID_DEVCLASS_PORTS, nCount, devInfo)
        If bResult Then
            'devInfo = New SP_DEVICE_INTERFACE_DATA()
            'devInfo.cbSize = Marshal.SizeOf(devInfo)
            sDevice = GetSetupRegSetting(hDevInfo, devInfo, DEVICEPROPERTYINDEX.SPDRP_FRIENDLYNAME)
            If sDevice = "" Then
                sDevice = GetSetupRegSetting(hDevInfo, devInfo, DEVICEPROPERTYINDEX.SPDRP_DEVICEDESC)
            End If
            Console.WriteLine(sDevice)
        Else
            Console.WriteLine(Err.LastDllError)

            Return Nothing
        End If
        nCount += 1
    Loop

End Function

'Private Shared Function GetSetupRegSetting(ByVal hDevInfo As IntPtr, ByVal DID As SP_DEVINFO_DATA, ByVal RegSetting As DEVICEPROPERTYINDEX) As String
Private Shared Function GetSetupRegSetting(ByVal hDevInfo As IntPtr, ByVal DID As SP_DEVICE_INTERFACE_DATA, ByVal RegSetting As DEVICEPROPERTYINDEX) As String
    Dim buffStr As String
    Dim buffLng As Long
    Dim regType As REGPROPERTYTYPES
    Dim bufferLen As Long
    Dim retVal As Long = SetupDiGetDeviceRegistryProperty(hDevInfo, DID, RegSetting, regType, "", 0&, bufferLen)
    If retVal = 0 Then
        'err.lastdllerror
        Dim se As Integer = Err.LastDllError
        If se = SetupErrors.ERROR_INSUFFICIENT_BUFFER Then
            Select Case regType
                Case REGPROPERTYTYPES.REG_SZ, REGPROPERTYTYPES.REG_MULTI_SZ, REGPROPERTYTYPES.REG_EXPAND_SZ, REGPROPERTYTYPES.REG_BINARY
                    buffStr = Space$(bufferLen)
                    retVal = SetupDiGetDeviceRegistryProperty(hDevInfo, DID, RegSetting, regType, buffStr, Len(buffStr), bufferLen)
                Case REGPROPERTYTYPES.REG_DWORD, REGPROPERTYTYPES.REG_DWORD_BIG_ENDIAN, REGPROPERTYTYPES.REG_DWORD_LITTLE_ENDIAN
                    'retVal = SetupDiGetDeviceRegistryProperty(hDevInfo, DID, RegSetting, regType, bufflng, Len(bufflng), bufferLen)
                    buffStr = CStr(buffLng)
                    buffLng = buffLng + 1
            End Select
            If retVal <> 0 Then
                Return Left$(buffStr, bufferLen - 1)
            Else
                Return ""
            End If
        ElseIf se <> SetupErrors.ERROR_INVALID_DATA Then
            Return ""
        End If
    End If
End Function

Public Shared Function GetPorts3() As serPort()
    'Dim GUID_DEVCLASS_PORTS As New Guid(&H4D36E978, &HE325, &H11CE, &HBF, &HC1, &H8, &H0, &H2B, &HE1, &H3, &H18)
    Dim h As IntPtr = SetupDiGetClassDevs(GUID_DEVCLASS_PORTS, 0, IntPtr.Zero, DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE)
    If h.ToInt32 <> -1 Then
        Dim Success As Boolean = True
        Dim i As Integer = 0
        While Success
            Dim dia As SP_DEVICE_INTERFACE_DATA = New SP_DEVICE_INTERFACE_DATA()
            dia.cbSize = Marshal.SizeOf(dia)
            Success = SetupDiEnumDeviceInterfaces(h, Nothing, GUID_DEVCLASS_PORTS, i, dia)
            If Success Then
                Dim da As SP_DEVINFO_DATA = New SP_DEVINFO_DATA()
                da.cbSize = Marshal.SizeOf(da)

                Dim didd As SP_DEVICE_INTERFACE_DETAIL_DATA = New SP_DEVICE_INTERFACE_DETAIL_DATA()
                If IntPtr.Size = 8 Then
                    didd.cbSize = 8
                Else
                    didd.cbSize = 4 + Marshal.SystemDefaultCharSize
                End If
                Dim nRequiredSize As Integer = 0
                Dim nBytes As Integer = 260
                If SetupDiGetDeviceInterfaceDetail(h, dia, didd, nBytes, nRequiredSize, da) Then
                    Console.WriteLine(didd.DevicePath)

                End If
            End If
            i += 1
        End While
    End If


End Function

Public Shared Function GetPorts2() As serPort()
    Dim NewDeviceInfoSet As IntPtr
    'Dim GUID_DEVCLASS_PORTS As New Guid(&H4D36E978, &HE325, &H11CE, &HBF, &HC1, &H8, &H0, &H2B, &HE1, &H3, &H18)
    NewDeviceInfoSet = SetupDiGetClassDevs(GUID_DEVCLASS_PORTS, 0, 0, DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE) ', DeviceInfoSet, 0, 0)
    If NewDeviceInfoSet.ToInt32 = -1 Then
        Console.WriteLine("SetupDiGetClassDevsEx failed")
        Return Nothing
    End If

    Dim sdid As SP_DEVICE_INTERFACE_DATA = New SP_DEVICE_INTERFACE_DATA
    sdid.cbSize = Marshal.SizeOf(sdid)
    If Not SetupDiEnumDeviceInterfaces(NewDeviceInfoSet, Nothing, GUID_DEVCLASS_PORTS, 0, sdid) Then
        Console.WriteLine("Couldn't enumerate devices ( {0} )", Marshal.GetLastWin32Error)
        Return Nothing
    End If

    Console.WriteLine("{0}", GUID_DEVCLASS_PORTS)
    Console.WriteLine("{0}", sdid.InterfaceClassGuid)
    Console.WriteLine("{0}", sdid.Flags)
    Dim da As SP_DEVINFO_DATA = New SP_DEVINFO_DATA()
    da.cbSize = Marshal.SizeOf(da)
    Dim didd As SP_DEVICE_INTERFACE_DETAIL_DATA = New SP_DEVICE_INTERFACE_DETAIL_DATA()
    If IntPtr.Size = 8 Then
        didd.cbSize = 8
    Else
        didd.cbSize = 4 + Marshal.SystemDefaultCharSize
    End If

    Dim pDevDetail As SP_DEVICE_INTERFACE_DETAIL_DATA = Nothing
    Dim nBytes As Integer = Marshal.SizeOf(didd)
    If SetupDiGetDeviceInterfaceDetail(NewDeviceInfoSet, sdid, didd, nBytes, 0, da) Then
        Dim ptrPrevious As IntPtr

    End If


End Function

Public Shared Function GetPorts7() As serPort()
    Dim searcher As System.Management.ManagementObjectSearcher
    Try
        Dim PNPIDs As String() = {}
        searcher = New System.Management.ManagementObjectSearcher("\\.\root\WMI", "SELECT InstanceName, PortName FROM MSSerial_PortName")

        For Each port As Management.ManagementObject In searcher.Get
            ReDim Preserve PNPIDs(PNPIDs.Length)
            PNPIDs(PNPIDs.GetUpperBound(0)) = port("InstanceName")
        Next
        searcher = New System.Management.ManagementObjectSearcher("\\.\root\cimv2", "SELECT * FROM Win32_PnPEntity")
        For Each Port As System.Management.ManagementObject In searcher.Get
            'If Port("ClassGUID").ToString = "{df799e12-3c56-421b-b298-b6d3642bc878}" Then
            Dim pnpID As String = Port("PNPDeviceID").ToString
            If Array.FindIndex(PNPIDs, Function(s As String) (String.Compare(s.Substring(0, s.LastIndexOf("_")).ToLower, pnpID.ToLower)) = 0) <> -1 Then

                'End If
                'If pnpids.FindIndex((Port("PNPDeviceID").ToString)
                For Each p As Management.PropertyData In Port.Properties
                    If Not p.IsArray Then
                        Console.WriteLine(p.Name & " - " & Port(p.Name))
                    End If
                Next
                'Console.WriteLine(Port("PortName") & " - " & Port("InstanceName"))
            End If
        Next
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try

    For Each port As String In Ports.SerialPort.GetPortNames
        Console.WriteLine(port)
        Dim comport As Ports.SerialPort = New Ports.SerialPort(port)

    Next
End Function
